/** create by liuhua at 2019年5月21日 下午2:47:51**/
package com.star.truffle.gateway.exception;

import java.util.HashMap;
import java.util.Map;

import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ResponseStatusException;

/**
 * 自定义异常处理
 * 
 * <p>
 * 异常时用JSON代替HTML异常信息
 * <p>
 * 
 */
public class JsonExceptionHandler extends DefaultErrorWebExceptionHandler {

  public JsonExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,
      ErrorProperties errorProperties, ApplicationContext applicationContext) {
    super(errorAttributes, resourceProperties, errorProperties, applicationContext);
  }

  /**
   * 获取异常属性
   */
  @Override
  protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
    int code = 500;
    Throwable error = super.getError(request);
    if (error instanceof ResponseStatusException) {
      ResponseStatusException exc = (ResponseStatusException) error;
      code = exc.getStatus().value();
    }else if (error instanceof NotFoundException) {
      code = 404;
    }
    return response(code, this.buildMessage(request, error));
  }

  /**
   * 指定响应处理方法为JSON处理的方法
   * 
   * @param errorAttributes
   */
  @Override
  protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
    return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
  }

  /**
   * 根据code获取对应的HttpStatus
   * 
   * @param errorAttributes
   */
  @Override
  protected HttpStatus getHttpStatus(Map<String, Object> errorAttributes) {
    int statusCode = (int) errorAttributes.get("code");
    return HttpStatus.valueOf(statusCode);
  }

  /**
   * 构建异常信息
   * 
   * @param request
   * @param ex
   * @return
   */
  private String buildMessage(ServerRequest request, Throwable ex) {
    StringBuilder message = new StringBuilder("Failed to handle request [");
    message.append(request.methodName());
    message.append(" ");
    message.append(request.uri());
    message.append("]");
    if (ex != null) {
      message.append(": ");
      message.append(ex.getMessage());
    }
    return message.toString();
  }

  /**
   * 构建返回的JSON数据格式
   * 
   * @param status       状态码
   * @param errorMessage 异常信息
   * @return
   */
  public static Map<String, Object> response(int status, String errorMessage) {
    Map<String, Object> map = new HashMap<>();
    map.put("code", status);
    map.put("msg", errorMessage);
    return map;
  }

}
